/**
 * http 请求封装
 * @author tangsj
 * @param {*} url 请求地址
 * @param {*} options 请求参数
 */
import config from '../config';
import utils from '../utils';
import store from "@/store";
import api from '@/api';
import { 
  removeUserToken,
} from "@/utils/auth";

// 记录请求中的请求数，控制loading显示
let requestCount = 0;
let hasError = false;
let isRefreshing = false; // 是否正在刷新 Token
let requestsQueue = []; // 用于存储等待刷新 Token 的请求队列

export function fetch(url, options) {
  const header = {
    Authorization: `Bearer ${store.getters.token}`,
  };
  
  options = Object.assign({
    loading: true,
    method: 'GET',
    data: {},
    holdTip: false,
  }, options);

  return new Promise((resolve, reject) => {
    if (requestCount === 0 && options.loading) {
      hasError = false;
    }

    requestCount += 1;

    const requestTask = uni.request({
      url: `${config.apiRoot}${url}`,
      data: options.data,
      method: options.method,
      header,
      success: (res) => {
        console.log(res)
        requestCount -= 1;
        if (res.data.code === 200) {
          resolve(res.data || {});
        } else if (res.data.code === 401 && store.getters.token) { // Token 过期
          if (!isRefreshing) {
            isRefreshing = true;
            // 将当前请求加入队列
            requestsQueue.push({ url, options, resolve, reject });

            // 调用刷新 Token 的接口
            api.user.refresh_token(store.getters.refresh_token).then(refreshRes => {
              if (refreshRes.code === 200) {
                // 更新 Token
                store.commit('SET_TOKEN', refreshRes.data.accessToken);
                store.commit('SET_REFRESH_TOKEN', refreshRes.data.refreshToken);

                // 重新发起队列中的请求
                requestsQueue.forEach(req => {
                  fetch(req.url, req.options).then(req.resolve).catch(req.reject);
                });

                // 清空队列
                requestsQueue = [];
              } else {
                // 刷新 Token 失败，提示用户重新登录
                uni.showToast({
                  title: '登录失效，请重新登录',
                  icon: 'none',
                });
                removeUserToken();
                uni.reLaunch({ url: '/pages/authorization/index' });
              }
              isRefreshing = false;
            }).catch(err => {
              console.error('Token 刷新失败', err);
              uni.showToast({
                title: '登录失效，请重新登录',
                icon: 'none',
              });
              removeUserToken();
              uni.reLaunch({ url: '/pages/authorization/index' });
              isRefreshing = false;
            });
          } else {
            // 如果已经在刷新 Token，将当前请求加入队列
            requestsQueue.push({ url, options, resolve, reject });
          }
        } else {
          // 其他错误
          resolve(res.data || {});
        }
      },
      fail: (err) => {
        console.log(err)
        requestCount -= 1;
        hasError = true;

        uni.showToast({
          title: '服务器异常！',
          icon: 'none',
        });

        reject({
          msg: '服务器异常！',
        });
      },
      complete: () => {
        if (requestCount === 0 && options.loading) {
          // 如果没有请求在进行中，隐藏 Loading
          uni.hideLoading();
        }
      },
    });

    // 如果没有加载提示，且请求失败，直接显示错误
    if (!options.loading && hasError) {
      uni.showToast({
        title: '请求失败，请稍后再试',
        icon: 'none',
      });
    }
  });
}

const http = {
  get(url, data = {}, options = {}) {
    return fetch(url, {
      method: 'GET',
      data: data.params,
      ...options,
    });
  },
  put(url, data = {}, options = {}) {
    return fetch(url, {
      method: 'PUT',
      data: data.params,
      ...options,
    });
  },
  delete(url, data = {}, options = {}) {
    return fetch(url, {
      method: 'DELETE',
      data: data.params,
      ...options,
    });
  },
  post(url, data = {}, options = {}) {
    if (data.params) {
      // 将param放到url 参数里面
      const query = utils.buildQueryString(data.params);
      url += `?${query}`;
      delete data.params;
    }
    return fetch(url, {
      method: 'POST',
      data,
      ...options,
    });
  },
};

export default http;